﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Utilities.StatisticLib
{
    public class StatisticLib
    {
        /// <summary>
        /// Get the maximum element index in a list
        /// </summary>
        /// <param name="lst">The input list of elements</param>
        /// <returns>The index of the maximum elements</returns>
        public static int MaxElementPos(List<int> lst)
        {
            return lst.IndexOf(lst.Max());
        }

        /// <summary>
        /// Get the minimum element index in a list
        /// </summary>
        /// <param name="lst">The input list of elements</param>
        /// <returns>The index of the minimum elements</returns>
        public static int MinElementPos(List<int> lst)
        {
            return lst.IndexOf(lst.Min());            
        }

        /// <summary>
        /// Measure the standard deviation of a list of elements.
        /// </summary>
        /// <param name="inputList">The input list</param>
        /// <returns>The standard deviation of this list.</returns>
        public static double MeasureStandardDeviation(List<int> inputList)
        {
            if (inputList.Count == 1)
            {
                return 0.0;
            }

            double mean = MeasureMean(inputList);

            double s = 0;
            foreach (int i in inputList)
            {
                s += (((1.0 * i) - mean) * ((1.0 * i) - mean));
            }

            return Math.Sqrt(s / (inputList.Count - 1));
        }

        /// <summary>
        /// Measure the mean value of a list.
        /// </summary>
        /// <param name="inputList">The input list.</param>
        /// <returns>The mean value of this list.</returns>
        public static double MeasureMean(List<int> inputList)
        {
            return (1.0 * inputList.Sum()) / inputList.Count;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="meanLst">List of mean values of each lists</param>
        /// <param name="SDLst">List of standard deviation values of each lists</param>
        /// <returns>The index of the the element with best mean and standard deviation</returns>
        public static int EvaluateMeanAndSD(List<double> meanLst, List<double> SDLst)
        {
            if (meanLst.Count != SDLst.Count)
            {
                return -1;
            }
            else
            {
                int chosenPos = 0;                

                for (int i = 1; i < meanLst.Count; i++)
                {
                    if (meanLst[i] > meanLst[chosenPos])
                    {
                        chosenPos = i;
                    }
                    else if (meanLst[i] == meanLst[chosenPos])
                    {
                        if (SDLst[i] < SDLst[chosenPos])
                        {
                            chosenPos = i;
                        }
                    }
                }

                return chosenPos;
            }
        }

        /// <summary>
        /// Measure the similarity of 2 vectors using cosine measurement.
        /// </summary>
        /// <param name="vector1">Vector 1</param>
        /// <param name="vector2">Vector 2</param>
        /// <returns>The similarity of 2 vectors</returns>
        public static double VectorSimilarity(List<double> vector1, List<double> vector2)
        {
            double dotProduct = 0.0;
            for (int i = 0; i < vector1.Count; i++)
            {
                dotProduct += (vector1[i] * vector2[i]);
            }
            return dotProduct / (Magnitude(vector1) * Magnitude(vector2));
        }

        /// <summary>
        /// Measure the magnitude of a vector
        /// </summary>
        /// <param name="vectorX">Vector X</param>
        /// <returns>The magnitude of a vector</returns>
        public static double Magnitude(List<double> vectorX)
        {
            double sum = 0.0;
            foreach (int i in vectorX)
            {
                sum += (i * i);
            }
            return Math.Sqrt(sum);
        }
    }
}
